package com.apes.scm.masterdata.product.es;

import com.apes.framework.api.DomainService;
import com.apes.framework.es.EsDsl;
import com.apes.framework.plugin.cache.Cache;
import com.apes.framework.plugin.esb.api.SimpleRequest;
import com.apes.framework.plugin.outbox.annotation.OutboxSubscriber;
import com.apes.framework.util.MapUtil;
import com.apes.framework.util.PinyinUtil;
import com.apes.framework.util.ReflectUtil;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.repository.ProductRepository;
import org.elasticsearch.index.IndexNotFoundException;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service("esProductService")
public class EsProductService extends DomainService {

    @Autowired
    private EsProductRepository repository;

    @Autowired
    private ProductRepository productRepository;

    @Value("${apes.es.tags:}")
    private String tags;

    @Autowired
    private Cache cache;

    public void init(SimpleRequest request) {
        String cacheId = "es.Product.init";
        Map row = request.getMap();
        int size = row.containsKey("size") ? Integer.valueOf(String.valueOf(row.get("size"))) : 2000;
        while (true) {
            Object v = cache.get(cacheId);
            String id = v == null ? "0000000000" : String.valueOf(v);
            List<Product> products = productRepository.findAllByIdGreaterThanOrderByIdAsc(id, PageRequest.of(0, size));
            List<EsProduct> esProducts = products.stream().map(product -> createEsProduct(product)).collect(Collectors.toList());
            if (esProducts.size() > 0) {
                repository.saveAll(esProducts);
            }
            if (products != null && products.size() > 0) {
                cache.put(cacheId, products.get(products.size() - 1).getId());
            }
            if (products.size() < size) {
                break;
            }
        }
    }

    @OutboxSubscriber(name = "商品导入搜索引擎：保存")
    public void save(Product product) {
        EsProduct esProduct = createEsProduct(product);
        repository.save(esProduct);
    }

    @OutboxSubscriber(name = "商品导入搜索引擎：删除", eventType = "D")
    public void delete(Product product) {
        try {
            if (StringUtils.hasText(tags)) {
                repository.deleteAllByTagsAndId(tags, product.getId());
            } else {
                repository.deleteAllById(product.getId());
            }
        } catch (IndexNotFoundException e) {
            e.printStackTrace();
        }
    }

    private EsProduct createEsProduct(Product product) {
        EsProduct esProduct = new EsProduct();
        ReflectUtil.copyAll(product, esProduct);
        esProduct.setInitials(getShortPinyin(esProduct.getName()));
        if (product.getProductGroup() != null) {
            esProduct.setProductGroupId(product.getProductGroup().getId());
            esProduct.setProductGroupQtyMgmt(product.getProductGroup().isQtyMgmt());
        }
        if (product.getBrand() != null) {
            esProduct.setBrandId(product.getBrand().getId());
        }
        if (product.getClassify() != null) {
            esProduct.setClassifyId(product.getClassify().getId());
        }
        if (StringUtils.hasText(tags)) {
            esProduct.setTags(tags);
        }
        return esProduct;
    }

    private String getShortPinyin(String name) {
        return PinyinUtil.getShortPinyin(name).replaceAll(" ", "");
    }

    private static final Map<String, String> mapping = MapUtil.mapper(
            "productGroup.id", "productGroupId",
            "productGroup.qtyMgmt", "productGroupQtyMgmt",
            "brand.id", "brandId",
            "classify.id", "classifyId"
    );

    public <R> R findProducts(SimpleRequest request) {
        Map row = request.getMap();
        PageRequest pageRequest;
        if (row.containsKey("page") && row.containsKey("size")) {
            pageRequest = PageRequest.of(request.get("page"), request.get("size"));
        } else {
            pageRequest = PageRequest.of(0, 1000);
        }
        QueryBuilder qb = EsDsl.build(request, mapping);
        Page<EsProduct> esProducts = repository.search(qb, pageRequest);
        List<Product> products = new ArrayList<>();
        for (EsProduct esProduct : esProducts) {
            products.add(productRepository.findOne(esProduct.getId()));
        }
        Page<Product> productPage = new PageImpl(products, esProducts.getPageable(), esProducts.getTotalElements());
        return MapUtil.mapped(productPage, "serveType"); //, "customMarker", "faCategory", "type", "tax", "brand", "category", "classify"
    }

}
